package cn.matezk.cloud.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.matezk.cloud.beans.BindDeviceRequest;
import cn.matezk.cloud.beans.DeviceSearch;
import cn.matezk.cloud.beans.Result;
import cn.matezk.cloud.beans.SimpleDevice;
import cn.matezk.cloud.dao.DeviceDao;
import cn.matezk.cloud.dao.FamilyMemberDao;
import cn.matezk.cloud.dao.UserDao;
import cn.matezk.cloud.dao.UserDeviceDao;
import cn.matezk.cloud.model.Device;
import cn.matezk.cloud.model.User;
import cn.matezk.cloud.model.UserDevice;
import cn.matezk.cloud.service.IMiniAppService;
import cn.matezk.cloud.service.ITencentService;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.iot.v20180123.IotClient;
import com.tencentcloudapi.iotexplorer.v20190423.IotexplorerClient;
import com.tencentcloudapi.iotexplorer.v20190423.models.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;

@Service
@Slf4j
public class MiniAppService implements IMiniAppService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private DeviceDao deviceDao;
    @Autowired
    private UserDeviceDao userDeviceDao;
    @Autowired
    private FamilyMemberDao familyMemberDao;
    @Autowired
    private IotexplorerClient tencentClient;
    @Autowired
    private ITencentService tencentService;
    @Autowired
    private IotClient iotClient;
    @Value("${tencent.iot-app-id}")
    private String iotAppId;
    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public Result wechatNotifyEnable(String unionId, String userId, Boolean wechatNotifyEnable) {
        User user = userDao.selectByPrimaryKey(unionId);
        if (ObjectUtil.isNull(user)) {
            user = new User();
            user.setUnionId(unionId);
            user.setUserId(userId);
            userDao.insertSelective(user);
            if (Boolean.TRUE.equals(wechatNotifyEnable)) {
                return Result.error("未关注公众号");
            }
        } else {
            user.setUserId(userId);
            user.setWechatNotifyEnable(wechatNotifyEnable);
            userDao.updateByPrimaryKeySelective(user);
            if (Boolean.FALSE.equals(user.getIsSub()) && Boolean.TRUE.equals(wechatNotifyEnable)) {
                return Result.error("未关注公众号");
            }
        }
        return Result.ok();
    }

    @Override
    public Boolean wechatNotifyEnable(String unionId) {
        User user = userDao.selectByPrimaryKey(unionId);
        if (ObjectUtil.isNull(user))    return false;
        return user.getWechatNotifyEnable();
    }

    public String aliasName(String productId, String deviceName) {
        String deviceId = productId.concat("/").concat(deviceName);
        Device device = deviceDao.selectByPrimaryKey(deviceId);
        return ObjectUtil.isNotNull(device) ? device.getAliasName() : null;
    }

    @Override
    public void updateDevice(Device device) {
        deviceDao.updateByPrimaryKeySelective(device);
    }

    @Override
    @Transactional
    public void bindFamily(BindDeviceRequest request) throws TencentCloudSDKException {
        // 查询产品
        DescribeStudioProductRequest productRequest = new DescribeStudioProductRequest();
        productRequest.setProductId(request.getProductId());
        DescribeStudioProductResponse productResponse = tencentClient.DescribeStudioProduct(productRequest);
        // 调用腾讯云接口绑定
        DirectBindDeviceInFamilyRequest bindRequest = new DirectBindDeviceInFamilyRequest();
        bindRequest.setUserID(request.getUserId());
        bindRequest.setIotAppID(iotAppId);
        bindRequest.setFamilyId(request.getFamilyId());
        bindRequest.setRoomId(request.getRoomId());
        bindRequest.setProductId(request.getProductId());
        bindRequest.setDeviceName(request.getDeviceName());
        tencentClient.DirectBindDeviceInFamily(bindRequest);
        // 查询设备是否存在
        Device device = deviceDao.selectByPrimaryKey(request.getDeviceId());
        String aliasName = (ObjectUtil.isNull(device) || ObjectUtil.isEmpty(device.getAliasName())) ? productResponse.getProduct().getProductName() : device.getAliasName();
        if ("tl".equals(env)) {
            aliasName = productResponse.getProduct().getProductName().concat("-").concat(request.getDeviceName().substring(request.getDeviceName().length() - 4));
        } else if ("ycg".equals(env)) {
            if ("MEKDW1P8N4".equals(request.getProductId())) {
                aliasName = "一门智能收发快递柜";
            }
        }
        if (ObjectUtil.notEqual(aliasName, productResponse.getProduct().getProductName())) {
            updateAliasName(request.getAccessToken(), request.getProductId(), request.getDeviceName(), aliasName);
        }
        // 数据库保存
        Device du = new Device();
        du.setAppId(iotAppId);
        du.setProductId(request.getProductId());
        du.setDeviceName(request.getDeviceName());
        du.setAliasName(aliasName);
        du.setFamilyId(request.getFamilyId());
        du.setRoomId(request.getRoomId());
        du.setLongitude(BigDecimal.ZERO);
        du.setLatitude(BigDecimal.ZERO);
        if (ObjectUtil.isNull(device)) {
            // 插入设备信息
            Calendar calendar = Calendar.getInstance();
            du.setExFactoryTime(calendar.getTime());
            calendar.add(Calendar.YEAR, 1);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.add(Calendar.DATE, -1);
            du.setExpireDate(calendar.getTime());
            deviceDao.insertSelective(du);
        } else {
            deviceDao.updateByPrimaryKeySelective(du);
            deviceDao.resetNotifyConfig(du.getDeviceId());
        }
        // 解绑
        userDeviceDao.unbindByDeviceId(request.getDeviceId());
        // 绑定设备和用户
        UserDevice ud = new UserDevice();
        ud.setDeviceId(request.getDeviceId());
        ud.setUserId(request.getUserId());
        ud.setRole(UserDevice.ROLE_OWNER); 
        ud.setBindTime(Calendar.getInstance().getTimeInMillis() / 1000);
        userDeviceDao.bind(ud);
    }

    @Override
    public Device detail(String deviceId) {
        return deviceDao.selectByPrimaryKey(deviceId);
    }

    @Override
    @Transactional
    public CallDeviceActionSyncResponse unbindDevice(String deviceId) throws TencentCloudSDKException {
        String productId = deviceId.split("/")[0];
        String deviceName = deviceId.split("/")[1];
        CallDeviceActionSyncRequest request = new CallDeviceActionSyncRequest();
        request.setProductId(productId);
        request.setDeviceName(deviceName);
        request.setActionId("unbind");
        CallDeviceActionSyncResponse response = tencentClient.CallDeviceActionSync(request);
        if (ObjectUtil.equals(response.getStatus(), "succ")) {
            deviceDao.unbind(deviceId);
            userDeviceDao.unbindByDeviceId(deviceId);
        }
        return response;
    }

    @Override
    public void joinFamily(String familyId, String userId) {
        familyMemberDao.bind(familyId, userId);
    }

    @Override
    public void removeFamily(String familyId, String userId) {
        familyMemberDao.unbind(familyId, userId);
    }

    @Override
    public void transferFamily(String familyId, String fromUserId, String toUserId) {
        userDeviceDao.changeFamilyDeviceOwner(familyId, fromUserId, toUserId);
    }

    @Override
    public List<SimpleDevice> deviceSearch(DeviceSearch deviceSearch) {
        return deviceDao.search(deviceSearch);
    }

    private void updateAliasName(String token, String productId, String deviceName, String aliasName) {
        // 修改设备别名
        JSONObject params = JSONUtil.createObj()
                .set("AccessToken", token)
                .set("Action", "AppUpdateDeviceInFamily")
                .set("ProductId", productId)
                .set("DeviceName", deviceName)
                .set("AliasName", aliasName);
        while (true) {
            try {
                tencentService.request(params);
                break;
            } catch (Exception ex) {
                if (ex instanceof TencentCloudSDKException) {
                    TencentCloudSDKException te = (TencentCloudSDKException)ex;
                    log.error("{}/{}修改别名{}失败: {}({})", productId, deviceName, aliasName, te.getMessage(), te.getErrorCode());
                    if ("InvalidParameterValue.DB_Update_0_ROWS".equals(te.getErrorCode())) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e){}
                        continue;
                    }
                }
                break;
            }
        }
    }
}
